package com.ywcq.netty.httpserver.helloworld;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;

/**
 * An HTTP server that sends back the content of the received HTTP request
 * in a pretty plaintext form.
 */
@Component
public final class HttpHelloWorldServer 
{
	
	 Logger logger = LogManager.getLogger();
	 
	 private Boolean isSsl = false;
	 
	 private Integer port;
	 
	 private Config config;


    public HttpHelloWorldServer()
    {
    }
    
    public void init(Config config)
    {
    	this.config = config;
    	this.port = config.getPort();
    	this.isSsl = config.getIsSsl();
    	logger.debug("init http server : " + config);
    }
    
    public void startServer() throws Exception 
    {
        final SslContext sslCtx;
        if (isSsl) {
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
        } else {
            sslCtx = null;
        }

        // Configure the server.
        EventLoopGroup bossGroup = new NioEventLoopGroup(config.getBoosGroupThreads());
        EventLoopGroup workerGroup = new NioEventLoopGroup(config.getWorkerGroupThreads());
        try {
            ServerBootstrap b = new ServerBootstrap();
            initConfig(b,config);
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .handler(new LoggingHandler(LogLevel.INFO))
             .childHandler(new HttpHelloWorldServerInitializer(sslCtx));
            
            Channel ch = b.bind(port).sync().channel();
            System.err.println("Open your web browser and navigate to " +
                    (isSsl? "https" : "http") + "://127.0.0.1:" + port + '/');

            ch.closeFuture().sync();
            System.out.println("finish ..........");
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

	private void initConfig(ServerBootstrap b, Config config) 
	{
		setSocketOption(b,config);
		
	}

	private void setSocketOption(ServerBootstrap b, Config config) 
	{
		resetSocketConfig(b,ChannelOption.SO_BACKLOG,config.getSocketOptionBacklog());
		resetSocketConfig(b,ChannelOption.SO_KEEPALIVE,config.getSocketOptionKeepalive());
		resetSocketConfig(b,ChannelOption.SO_SNDBUF,config.getSocketOptionSendBuffer());
		resetSocketConfig(b,ChannelOption.SO_RCVBUF,config.getSocketOptionRecieveBuffer());
		resetSocketConfig(b,ChannelOption.SO_REUSEADDR,config.getSocketOptionReuseAddr());
		resetSocketConfig(b,ChannelOption.SO_LINGER,config.getSocketOptionLinger());
		resetSocketConfig(b,ChannelOption.SO_TIMEOUT,config.getSocketOptionTimeOut());
		resetSocketConfig(b,ChannelOption.SO_BROADCAST,config.getSocketOptionBroadcast());
		resetSocketConfig(b,ChannelOption.ALLOW_HALF_CLOSURE,config.getSocketOptionAllowHalfClosure());
		
	}
	
	private <T> void resetSocketConfig(ServerBootstrap b, ChannelOption<T> option, T value)
	{
		if (null != value)
		{
			logger.debug("set socket option: " + option + "=" + value);
			b.option(option, value);
		}
		else
		{
			logger.debug("socket option " + option +" use default value!");
		}
	}
	
}